package com.carter.springframework.context.support;

import com.carter.springframework.beans.exception.BeanException;
import com.carter.springframework.beans.factory.ConfigurableListableBeanFactory;
import com.carter.springframework.beans.factory.config.BeanDefinitionRegistryPostProcessor;
import com.carter.springframework.beans.factory.config.BeanPostProcessor;
import com.carter.springframework.beans.factory.support.BeanDefinitionRegistry;
import com.carter.springframework.beans.factory.support.BeanFactoryPostProcessor;
import com.carter.springframework.context.ApplicationEvent;
import com.carter.springframework.context.ApplicationListener;
import com.carter.springframework.context.ConfigurableApplicationContext;
import com.carter.springframework.context.event.ApplicationEventMulticaster;
import com.carter.springframework.context.event.ContextClosedEvent;
import com.carter.springframework.context.event.ContextRefreshEvent;
import com.carter.springframework.context.event.SimpleApplicationEventMulticaster;
import com.carter.springframework.core.io.DefaultResourceLoader;

import java.util.Map;


public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext{
    private ApplicationEventMulticaster applicationEventMulticaster;
    @Override
    public void refresh() throws BeanException{
        //创建BeanFactory,加载BeanDefinition
        refreshBeanFactory();
        //获取beanFactory
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        //添加ApplicationContextAwareProcessor
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
        //在bean实例化之前，执行BeanFactoryPostProcessor
        invokeBeanFactoryPostProcessors(beanFactory);
        //注册BeanPostProcessor
        registerBeanPostProcessors(beanFactory);
        //初始化事件发布者
        initApplicationEventMulticaster();
        //注册事件监听器
        registerListeners();
        //提前实例化单例bean对象
        beanFactory.preInstantiateSingletons();
        //结束刷新
        finishRefresh();
    }

    private void finishRefresh() {
        publishEvent(new ContextRefreshEvent(this));
    }

    /**
     * 注册监听器
     */
    private void registerListeners() {
        for (ApplicationListener listener : getBeansOfType(ApplicationListener.class).values()) {
            applicationEventMulticaster.addApplicationListener(listener);
        }
    }



    /**
     * 初始化事件广播
     */
    private void initApplicationEventMulticaster() {
       this.applicationEventMulticaster = new SimpleApplicationEventMulticaster();
       getBeanFactory().addSingleton("applicationEventMulticaster",applicationEventMulticaster);
    }

    /**
     * 注册beanPostProcessor
     * @param beanFactory
     * @throws BeanException
     */
    private void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) throws BeanException{
        for (BeanPostProcessor  processor : beanFactory.getBeansOfType(BeanPostProcessor.class).values()) {
            beanFactory.addBeanPostProcessor(processor);
        }
    }

    /**
     * 调用beanFactoryPostProcessor
     * @param beanFactory
     * @throws BeanException
     */
    private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) throws BeanException{
        for (BeanFactoryPostProcessor processor : beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values()) {
            //如果处理器为bean定义后置处理器，则先处理这个
            if (processor instanceof BeanDefinitionRegistryPostProcessor){
                ((BeanDefinitionRegistryPostProcessor) processor).postProcessBeanDefinitionRegistry((BeanDefinitionRegistry) beanFactory);
            }
            processor.postProcessBeanFactory(beanFactory);
        }
    }

    /**
     * 获取BeanFactory
     * @return
     */
    @Override
    public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;

    /**
     * 刷新beanFactory
     * @throws BeanException
     */
    protected abstract void refreshBeanFactory() throws BeanException;

    @Override
    public Object getBean(String beanName,Object... args) throws BeanException{
        return getBeanFactory().getBean(beanName,args);
    }

    @Override
    public <T> T getBean(String beanName, Class<T> requiredType) throws BeanException {
        return  getBeanFactory().getBean(beanName, requiredType);
    }

    @Override
    public <T> Map<String,T> getBeansOfType(Class<T> type) throws BeanException {
        return getBeanFactory().getBeansOfType(type);
    }

    @Override
    public String[] getBeanDefinitionNames() {
        return getBeanFactory().getBeanDefinitionNames();
    }

    @Override
    public void registerShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread(this::close));
    }

    @Override
    public void close() {
        //发布容器关闭事件
        publishEvent(new ContextClosedEvent(this));
        //销毁单例对象
        getBeanFactory().destroySingletons();
    }

    @Override
    public void publishEvent(ApplicationEvent applicationEvent) {
        applicationEventMulticaster.multicastEvent(applicationEvent);
    }
}
